﻿#ifndef COMCOMMON_H
#define COMCOMMON_H
#include <QSerialPort>
#include <QDataStream>
#include <QModbusDataUnit>



enum ComState{
    CS_Invalid = 0,
    CS_Connected,
    CS_UnConnected
};

//串口配置文件
struct SerialComConfig{
    QString name;//串口自定义名称
    QString comId;//串口号
    qint32 baudRate;//波特率
    QSerialPort::DataBits dataBits;//数据位
    QSerialPort::Parity parity;//校验
    QSerialPort::StopBits stopBits;//停止位
    QSerialPort::FlowControl flowControl;//流控制
    bool mIsSendHex;//以十六进制发送
    SerialComConfig() :name(""), comId("COM1"), baudRate(QSerialPort::Baud9600), dataBits(QSerialPort::Data8), parity(QSerialPort::NoParity),
        stopBits(QSerialPort::OneStop), flowControl(QSerialPort::NoFlowControl){}
    SerialComConfig(QString name, QString na, qint32 baud, QSerialPort::DataBits databit, QSerialPort::Parity par, QSerialPort::StopBits stop,
                    QSerialPort::FlowControl control, bool isSendHex) {
        this->name = name;
        comId = na;
        baudRate = baud;
        dataBits = databit;
        parity = par;
        stopBits = stop;
        flowControl = control;
        mIsSendHex = isSendHex;
    }
    ~SerialComConfig(){}
    friend QDataStream &operator<<(QDataStream &out, const SerialComConfig &config)
    {
        out << config.name
            << config.comId
            << config.baudRate
            << config.dataBits
            << config.parity
            << config.stopBits
            << config.flowControl
            << config.mIsSendHex;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, SerialComConfig &config)
    {
        in  >> config.name
            >> config.comId
            >> config.baudRate
            >> config.dataBits
            >> config.parity
            >> config.stopBits
            >> config.flowControl
            >> config.mIsSendHex;
        return in;
    }
};
Q_DECLARE_METATYPE(SerialComConfig)

struct TcpComConfig{
    QString name;//自定义名称
    QString mOpponentIP;//对方IP
    int mOpponentPort;//对方端口
    QString mLocalIP;//本地IP
    int mLocalPort;//本地端口
    bool mIsSendHex;//以十六进制发送
    TcpComConfig() :name(""), mOpponentIP("127.0.0.1"), mOpponentPort(10000), mLocalIP("127.0.0.1"), mLocalPort(10000),
        mIsSendHex(true){}
    TcpComConfig(QString name, QString opponentIP, int opponentPort, QString localIP, int localPort, bool isSendHex, bool isDisplayHex) {
        this->name = name;
        mOpponentIP = opponentIP;
        mOpponentPort = opponentPort;
        mLocalIP = localIP;
        mLocalPort = localPort;
        mIsSendHex = isSendHex;
    }
    ~TcpComConfig(){}
    friend QDataStream &operator<<(QDataStream &out, const TcpComConfig &config)
    {
        out << config.name
            << config.mOpponentIP
            << config.mOpponentPort
            << config.mLocalIP
            << config.mLocalPort
            << config.mIsSendHex;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, TcpComConfig &config)
    {
        in  >> config.name
            >> config.mOpponentIP
            >> config.mOpponentPort
            >> config.mLocalIP
            >> config.mLocalPort
            >> config.mIsSendHex;
        return in;
    }
};
Q_DECLARE_METATYPE(TcpComConfig)

enum UdpSendType{
    UST_Unicast = 0,//单播
    UST_Broadcast, //广播
    UST_Multicast//组播
};

struct UdpComConfig{
    QString name;//自定义名称
    QString mOpponentIP;//对方IP
    int mOpponentPort;//对方端口
    QString mLocalIP;//本地IP
    int mLocalPort;//本地端口
    UdpSendType mSendType;//记录UDP消息传送模式 0:单播 1:广播 2:组播（多播）
    bool mIsSendHex;//以十六进制发送
    UdpComConfig() :name(""), mOpponentIP("127.0.0.1"), mOpponentPort(10000), mLocalIP("127.0.0.1"), mLocalPort(10000),
        mSendType(UST_Unicast), mIsSendHex(true){}

    UdpComConfig(QString name,QString opponentIP, int opponentPort, QString localIP, int localPort, int sendType, bool isSendHex) {
        this->name = name;
        mOpponentIP = opponentIP;
        mOpponentPort = opponentPort;
        mLocalIP = localIP;
        mLocalPort = localPort;
        mSendType = UdpSendType(sendType);
        mIsSendHex = isSendHex;
    }
    ~UdpComConfig(){}
    friend QDataStream &operator<<(QDataStream &out, const UdpComConfig &config)
    {
        out << config.name
            << config.mOpponentIP
            << config.mOpponentPort
            << config.mLocalIP
            << config.mLocalPort
            << config.mSendType
            << config.mIsSendHex;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, UdpComConfig &config)
    {
        in  >> config.name
            >> config.mOpponentIP
            >> config.mOpponentPort
            >> config.mLocalIP
            >> config.mLocalPort
            >> config.mSendType
            >> config.mIsSendHex;
        return in;
    }
};
Q_DECLARE_METATYPE(UdpComConfig)

enum ComClientType
{
    CCT_Tcp = 0,
    CCT_Serial,
    CCT_Udp
};

struct ComClientConfig
{
    QString name;//自定义名称
    ComClientType type;//类型
    bool isSendHex;//是否发送十六进制
    UdpComConfig udp;//udp配置
    TcpComConfig tcp;//tcp配置
    SerialComConfig serial;//串口配置
    ComClientConfig() : name(""), type(CCT_Tcp), isSendHex(true), udp(UdpComConfig()), tcp(TcpComConfig()), serial(SerialComConfig()){}

    ~ComClientConfig(){}
    friend QDataStream &operator<<(QDataStream &out, const ComClientConfig &config)
    {
        out << config.name
            << config.type
            << config.isSendHex
            << config.tcp
            << config.serial
            << config.udp;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, ComClientConfig &config)
    {
        in  >> config.name
            >> config.type
            >> config.isSendHex
            >> config.tcp
            >> config.serial
            >> config.udp;
        return in;
    }
};
Q_DECLARE_METATYPE(ComClientConfig)


enum ValueType{
    VT_Bool = 0,
    VT_Int16,
    VT_Int32,
    VT_Float
};
Q_DECLARE_METATYPE(ValueType)

static QMap<ValueType, QString> valueTypeString = {{VT_Bool, "Bool"},{VT_Int16, "Int16"},{VT_Int32, "Int32"},{VT_Float, "Float"}};

struct ModbusValue{
    ValueType valueType;//值类型
    qint16 addr;//相对地址，绝对地址需要加上起始地址
    qint16 valueI;//int值
    qint32 valueDI;//int32值
    float valueF;//float值
    ModbusValue():valueType(VT_Int16), addr(100), valueI(0), valueDI(0), valueF(.0){}
    friend QDataStream &operator<<(QDataStream &out, const ModbusValue &value)
    {
        out << value.valueType
            << value.addr
            << value.valueI
            << value.valueDI
            << value.valueF;
        ;
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, ModbusValue &value)
    {
        in  >> value.valueType
            >> value.addr
            >> value.valueI
            >> value.valueDI
            >> value.valueF
            ;
        return in;
    }
};
Q_DECLARE_METATYPE(ModbusValue)
enum PLCRequestType{
    PRT_Read = 0,
    PRT_Write,
};

struct PLCRequestData{
    PLCRequestType requestType;
    QModbusDataUnit::RegisterType table; //寄存器类型
    int addrStart;//起始地址
    QList<ModbusValue> data;//数据
    PLCRequestData():table(QModbusDataUnit::HoldingRegisters), addrStart(100), data(QList<ModbusValue>()){}
    ~PLCRequestData(){}
    int getAddrSize(){
        int size = 0;
        for(auto value : data){
            ValueType type = value.valueType;
            if(type == VT_Int16 || type == VT_Bool){
                size += 1;
            } else if(type == VT_Float || type == VT_Int32){
                size += 2;
            }
        }
        return size;
    }
    friend QDataStream &operator<<(QDataStream &out, const PLCRequestData &config)
    {
        out << config.requestType
            << config.table
            << config.addrStart
            << config.data.count();
        ;
        for(auto value : config.data){
            out << value;
        }
        return out;
    }
    friend QDataStream &operator>>(QDataStream &in, PLCRequestData &config)
    {
        int count = 0;
        in  >> config.requestType
            >> config.table
            >> config.addrStart
            >> count;
        config.data.clear();
        for(int i = 0; i < count; ++i){
            ModbusValue value;
            in >> value;
            config.data << value;
        }
        return in;
    }
};
Q_DECLARE_METATYPE(PLCRequestData)

//两个int16转float
static float int162float(qint16 val1, qint16 val2){
    float val = 0.0;
    int16_t *pb1 = (int16_t *)(&val);
    int16_t *pb2 = pb1+1;
    *pb1 = val1;
    *pb2 = val2;
    return val;
}
static int32_t int162int32(qint16 val1, qint16 val2){
    int32_t val = 0;
    int16_t *pb1 = (int16_t *)(&val);
    int16_t *pb2 = pb1+1;
    *pb1 = val1;
    *pb2 = val2;
    return val;
}

//float 转两个int16
static QList<qint16> float2int16(float val){
    int16_t *pb1 = (int16_t *)(&val);
    int16_t *pb2 = pb1+1;
    QList<qint16> lstInt;
    lstInt << pb1[0] << pb2[0];
    return lstInt;
}
static void int32ToInt16(int32_t value, int16_t &valueHigh, int16_t &valueLow){
    valueHigh = value >> 16;
    valueLow = value & 0xffff;
}
static int byteArray2Int(QByteArray array){
    return array.toHex().toInt(nullptr,16);
}

static int byteArray2Float(QByteArray array){
    if(false){
        std::reverse(array.begin(), array.end());
    }
    float floatData;
    memcpy(&floatData, array.data(), array.size());
    return floatData;
}


#endif // COMCOMMON_H
